﻿using System;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Messaging;

namespace SilverTrace
{
    public partial class MainPage : UserControl
    {
        private const int MAX_ELEMENTS = 5;
        private const int MAX_TEXT_LENGTH = 100000;

        private const string KEY_CURRENT_CONNECTION_NAME = "SilverTrace.KEY_CURRENT_CONNECTION_NAME";
        private const string KEY_ALL_CONNECTIONS = "SilverTrace.KEY_ALL_CONNECTIONS";

        private LinkedList<string> _connections;

        private LocalMessageReceiver _currentReceiver;

        private static readonly LinkedList<LocalMessageReceiver> _all = new LinkedList<LocalMessageReceiver>();

        public MainPage()
        {
            InitializeComponent();
            Application.Current.InstallStateChanged += 
                (sender, args) => DetouchButton.Visibility = 
                                        Application.Current.InstallState == InstallState.Installed 
                                            ? Visibility.Collapsed
                                            : Visibility.Visible;
            if (Application.Current.InstallState == InstallState.Installed)
            {
                DetouchButton.Visibility = Visibility.Collapsed;
            }
            InitializeInputs();
            
        }

        private void InitializeInputs()
        {
            this._connections = SetLinkedList(KEY_ALL_CONNECTIONS);

            PopulateConnectionsList();

        }

        private void StartListening()
        {
            if(ConnectionsList.SelectedIndex < 0) return;

            var connection = CurrentConnectionName;

            foreach (var curr in _all)
            {
                curr.MessageReceived -= CurrentReceiver_MessageReceived;
                curr.Dispose();
            }
            _all.Clear();
            this._currentReceiver = new LocalMessageReceiver(connection,  ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);
            this._currentReceiver.MessageReceived += CurrentReceiver_MessageReceived;
            _all.AddLast(this._currentReceiver);
            try
            {
                this._currentReceiver.Listen();
            }
            catch(ListenFailedException)
            {
                MessageBox.Show("There is already registered listener listening for connection:" + connection);
            }
            
            

        }

        private void CurrentReceiver_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            if (_isPaused) return;
            var sb = new StringBuilder(Data.Text);
            sb.AppendLine("-----------------------------------");
            sb.Append(DateTime.Now.ToString());
            sb.AppendLine(":");
            sb.AppendLine(e.Message);
            if (sb.Length > MAX_TEXT_LENGTH)
            {
                sb.Remove(0, sb.Length - MAX_TEXT_LENGTH);
            }
            Data.Text = sb.ToString();
            if (sb.Length > 0) Data.SelectionStart = sb.Length;
        }

        private static LinkedList<string> SetLinkedList(string key)
        {
            LinkedList<string> list;
            if (!IsolatedStorageSettings.ApplicationSettings.TryGetValue(key, out list))
            {
                IsolatedStorageSettings.ApplicationSettings[key] = list = new LinkedList<string>();
            }
            return list;
        }

        private bool _within_PopulateConnectionsList;
        private void PopulateConnectionsList()
        {
            if(_within_PopulateConnectionsList) return;
            _within_PopulateConnectionsList = true;
            var connections = this._connections.OrderBy(c => c);
            ConnectionsList.Items.Clear();

            string current;
            IsolatedStorageSettings.ApplicationSettings.TryGetValue(KEY_CURRENT_CONNECTION_NAME, out current);

            foreach (var connection in connections)
            {
                var isSelected = String.Equals(current, connection, StringComparison.OrdinalIgnoreCase); 
                ConnectionsList.Items.Add(new ComboBoxItem{Content = connection, IsSelected = isSelected});
            }
            _within_PopulateConnectionsList = false;

            StartListening();
            
        }


        protected string CurrentConnectionName
        {
            get
            {
                if (ConnectionsList.SelectedIndex < 0) return null;
                return ((ListBoxItem)(ConnectionsList.SelectedItem)).Content.ToString();
            }
            set
            {
                if(!ConnectionsList.Items.Cast<ComboBoxItem>().Any(cbi => String.Equals(cbi.Content.ToString(), value, StringComparison.OrdinalIgnoreCase)))
                {
                    this._connections.AddLast(value);
                    if (this._connections.Count > MAX_ELEMENTS) this._connections.RemoveFirst();
                    IsolatedStorageSettings.ApplicationSettings[KEY_ALL_CONNECTIONS] = this._connections;
                }
                IsolatedStorageSettings.ApplicationSettings[KEY_CURRENT_CONNECTION_NAME] = value;
                
                PopulateConnectionsList();
            }
        }

        protected string NewConnectionName
        {
            get
            {
                return NewConnectionNameTxt.Text.Trim();
            }
        }

        

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            this.AddNewConnection();
        }

        private void AddNewConnection()
        {
            if(NewConnectionName == "")
            {
                MessageBox.Show("Please specify the name of the new connection.");
                return;
            }
            CurrentConnectionName = NewConnectionName;
        }

        private void DetouchButton_Click(object sender, RoutedEventArgs e)
        {
            if (Application.Current.InstallState == InstallState.Installed)
            {
                MessageBox.Show("Application is already installed on the desktop.");
                return;
            }
            try
            {
                Application.Current.Install(); // take the app out of browser
            }
            catch (Exception ex)
            {
                MessageBox.Show("Application could not be installed on the desktop." + Environment.NewLine + ex.Message);
            }
        }

        private void ClearButton_Click(object sender, RoutedEventArgs e)
        {

            Data.Text = "";

        }

        private void ConnectionsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_within_PopulateConnectionsList) return;
            var combo = sender as ComboBox;
            IsolatedStorageSettings.ApplicationSettings[KEY_CURRENT_CONNECTION_NAME] = ((ListBoxItem)(combo.SelectedItem)).Content.ToString();

            PopulateConnectionsList();
        }

        private bool _isPaused;
        private void PauseButton_Click(object sender, RoutedEventArgs e)
        {
            PauseButton.Content = _isPaused ? "Pause" : "Restart";
            _isPaused = !_isPaused;
        }

        private void NewConnectionNameTxt_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.Key == Key.Enter)
            {
                this.AddNewConnection();
            }
        }

    }
}
